"""
40Seas 支付渠道实现
整合了40Seas API客户端和支付渠道逻辑
"""

import json
import requests
import time
import hmac
import base64
import hashlib
import datetime
import uuid
from typing import Dict, Any
import frappe
from .base import PaymentChannelBase


# 40Seas API 枚举定义
class CheckoutStatus:
    """结账状态枚举"""
    PENDING = "pending"
    CONFIRMED = "confirmed"
    INITIATED = "initiated"
    IN_TRANSIT = "in-transit"
    SCHEDULED = "scheduled"
    PARTIALLY_PAID = "partially-paid"
    PARTIALLY_REFUNDED = "partially-refunded"
    CHARGED = "charged"
    FAILED = "failed"
    CANCELED = "canceled"
    REFUNDED = "refunded"
    REFUND_INITIATED = "refund-initiated"
    REFUND_FAILED = "refund-failed"
    DISPUTED = "disputed"
    MARKED_AS_PAID = "marked-as-paid"
    OVERDUE = "overdue"
    DEFAULTED = "defaulted"


class PaymentMethod:
    """支付方式枚举"""
    CREDIT = "credit"
    ACH = "ach"
    PHONE = "phone"
    WIRE = "wire"
    CHECK = "check"


class PaymentTerm:
    """支付期限枚举"""
    IMMEDIATE = "immediate"  # 立即支付
    NET_30 = "net30"         # 30天账期
    NET_60 = "net60"         # 60天账期
    NET_90 = "net90"         # 90天账期


class Currency:
    """货币枚举"""
    USD = "USD"
    # 注意：40Seas API 目前只支持 USD
    # 如果需要支持其他货币，需要联系 40Seas 确认


class FortySeasClient:
    """40Seas API 客户端"""
    
    def __init__(self, client_id: str = None, client_secret: str = None):
        self.host = "https://api.40seas.com"
        # 这里的默认值不再写死测试/生产参数，实际生效的配置由 PaymentManager._get_channel_configs 提供
        # 若有特殊需要，可在初始化 FortySeasChannel 时通过 config 显式传入 client_id/client_secret
        self.clientId = client_id or ""
        self.clientsecret = client_secret or ""

        self.accessToken = ""
        self.expiresIn = 0
        self.session = requests.Session()

    def get_headers(self):
        headers = {
            "Content-Type": "application/json",
            "authorization": f"Bearer "+str(self.accessToken)
        }
        return headers

    def get_access_token(self):
        if self.accessToken and time.time() * 1000 < self.expiresIn:
            return self.accessToken
        # 40Seas 新版正式环境认证地址
        # 旧：https://auth.40seas.com/oauth/token
        # 新：https://api.40seas.com/v1/auth
        url = self.host + "/v1/auth"
        data = {
            "grant_type": "client_credentials",
            "client_id": self.clientId,
            "client_secret": self.clientsecret
        }
        resp = self.session.post(url, json=data).json()
        self.accessToken = resp.get('access_token', '')
        self.expiresIn = int(resp.get('expires_in', 0)) + int(time.time() * 1000)
        return self.accessToken

    def _request(self, url, method, headers=None, params=None, data=None, files=None):
        full_url = self.host + url
        if method.lower() == "get":
            r = self.session.get(full_url, headers=headers, params=params)
        elif method.lower() == "post":
            if files:
                r = self.session.post(full_url, headers=headers, files=files, data=data)
            else:
                r = self.session.post(full_url, headers=headers, json=data)
        elif method.lower() == "put":
            r = self.session.put(full_url, headers=headers, json=data)
        elif method.lower() == "patch":
            r = self.session.patch(full_url, headers=headers, json=data)
        elif method.lower() == "delete":
            r = self.session.delete(full_url, headers=headers, params=params)
        return r.json()

    def get_buyers(self):
        """获取买家列表"""
        token = self.get_access_token()
        url = "/v1/buyers"
        headers = self.get_headers()
        return self._request(url, "get", headers=headers)

    def create_buyer(self, display_name, address, email=None, legal_name=None, website=None, phone=None, 
                     dba=None, external_id=None, identification=None, contacts=None, 
                     requested_credit_amount=None, currency="USD", payment_options=None):
        """
        创建买家
        
        Args:
            display_name (str): 显示名称 (必需)
            address (dict): 地址信息 (必需) - 格式: {"country": "US"}
            email (str, optional): 邮箱
            legal_name (str, optional): 法定名称
            website (str, optional): 网站
            phone (str, optional): 电话号码
            dba (list, optional): 经营名称列表
            external_id (str, optional): 外部ID
            identification (dict, optional): 身份信息 - 格式: {"type": "ein"}
            contacts (list, optional): 联系人列表
            requested_credit_amount (float, optional): 请求信用额度
            currency (str, optional): 货币类型，默认USD
            payment_options (dict, optional): 支付选项
        
        Returns:
            dict: 创建结果
        """
        token = self.get_access_token()
        url = "/v1/buyers"
        headers = self.get_headers()
        
        # 构建必需参数
        data = {
            "displayName": display_name,
            "address": address
        }
        
        # 添加可选参数
        if email:
            data["email"] = email
        if legal_name:
            data["legalName"] = legal_name
        if website:
            data["website"] = website
        if phone:
            data["phone"] = phone
        if dba:
            data["dba"] = dba
        if external_id:
            data["externalId"] = external_id
        if identification:
            data["identification"] = identification
        if contacts:
            data["contacts"] = contacts
        if requested_credit_amount:
            data["requestedCreditAmount"] = requested_credit_amount
        if currency:
            data["currency"] = currency
        if payment_options:
            data["paymentOptions"] = payment_options
            
        return self._request(url, "post", headers=headers, data=data)

    def create_checkout(self, buyer_id, amount, currency="USD", metadata=None):
        """
        创建结账表单（简化版）
        
        Args:
            buyer_id (str): 买家ID
            amount (float): 金额
            currency (str): 货币类型，默认USD
            metadata (dict, optional): 元数据
        
        Returns:
            dict: 结账表单信息
        """
        token = self.get_access_token()
        url = "/v1/checkout"
        headers = self.get_headers()
        
        # 生成唯一的结账ID
        checkout_id = f"checkout_{uuid.uuid4().hex[:16]}"
        
        # 构建数据 - 只包含当前 API 支持的字段
        data = {
            "buyer": buyer_id,
            "amount": amount,
            "currency": currency,
            # 只指定立即支付，不再传 allowPartialPayments（新版 schema 不再支持该字段）
            "paymentTerms": ["immediate"],
        }
        
        if metadata:
            data["metadata"] = metadata

        resp = self._request(url, "post", headers=headers, data=data)
        return resp

    def create_payment_intent(self, checkout_id):
        """
        创建支付意图（返回支付链接）
        
        Args:
            checkout_id (str): 结账表单ID
        
        Returns:
            dict: 支付意图信息，包含 token, url 等
        """
        token = self.get_access_token()
        url = "/v1/intents/checkout"
        headers = self.get_headers()
        
        checkout_data = {"checkout": checkout_id}
        return self._request(url, "post", headers=headers, data=checkout_data)

    def get_checkout_status(self, checkout_id):
        """
        获取结账状态（用于webhook验证）
        
        Args:
            checkout_id (str): 结账表单ID
        
        Returns:
            dict: 结账状态信息
        """
        token = self.get_access_token()
        url = f"/v1/checkout/{checkout_id}"
        headers = self.get_headers()
        return self._request(url, "get", headers=headers)


class FortySeasChannel(PaymentChannelBase):
    """40Seas 支付渠道"""
    
    def __init__(self, config: Dict[str, Any]):
        super().__init__(config)
        self.client = FortySeasClient(
            client_id=config.get('client_id'),
            client_secret=config.get('client_secret')
        )
    
    def get_required_config_fields(self) -> list:
        return ['client_id', 'client_secret', 'seller_id']
    
    def get_display_name(self) -> str:
        return "40Seas 支付"
    
    def get_supported_currencies(self) -> list:
        return ['USD', 'EUR', 'GBP', 'CAD', 'AUD']
    
    def get_supported_payment_methods(self) -> list:
        return ['card', 'ach', 'wire']
    
    def get_buyer_by_external_id(self, external_id: str) -> Dict[str, Any]:
        """根据external_id获取现有买家"""
        try:
            if not self.validate_config():
                raise Exception("40Seas 配置不完整")
            
            # 调用40Seas API获取买家列表
            buyers_response = self.client.get_buyers()
            
            
            if buyers_response and isinstance(buyers_response, dict):
                # 检查是否有results字段（40Seas API的实际结构）
                if 'results' in buyers_response:
                    buyers_list = buyers_response.get('results', [])
                    
                    # 在买家列表中查找匹配的external_id
                    for buyer in buyers_list:
                        if isinstance(buyer, dict) and buyer.get('externalId') == external_id:
                            buyer_id = buyer.get('id') or buyer.get('buyerId') or buyer.get('buyer_id')
                            if buyer_id:
                                return {
                                    "success": True,
                                    "buyer_id": buyer_id,
                                    "data": buyer
                                }
                    
                    # 如果没有找到匹配的买家
                    return {
                        "success": False,
                        "error": f"未找到external_id为{external_id}的买家"
                    }
                else:
                    return {
                        "success": False,
                        "error": f"获取买家列表失败: 响应格式错误，缺少results字段"
                    }
            else:
                return {
                    "success": False,
                    "error": "获取买家列表响应格式错误"
                }
                
        except Exception as e:
            frappe.logger().error(f"[40Seas] 获取买家失败: {str(e)}")
            return {
                "success": False,
                "error": f"获取买家失败: {str(e)}"
            }

    def create_buyer(self, email: str, display_name: str, country: str, **kwargs) -> Dict[str, Any]:
        """创建40Seas买家"""
        try:
            if not self.validate_config():
                raise Exception("40Seas 配置不完整")

            # 40Seas 要求 address.country 为 ISO2 大写编码，这里再兜底统一转大写
            country_code = (country or "US").upper()
            
            buyer_data = self.client.create_buyer(
                display_name=display_name,
                address={"country": country_code},
                email=email,
                phone=kwargs.get('phone'),
                external_id=email
            )
            
            # 检查是否返回错误
            if isinstance(buyer_data, dict) and buyer_data.get('statusCode') == 400:
                if buyer_data.get('code') == 'buyer_external_id_already_exists':
                    # 买家已存在，尝试获取现有买家
                    try:
                        # 调用获取买家的API
                        existing_buyer = self.get_buyer_by_external_id(email)
                        if existing_buyer and existing_buyer.get('success'):
                            buyer_id = existing_buyer.get('buyer_id')
                            return {
                                "success": True,
                                "buyer_id": buyer_id,
                                "data": {"message": "买家已存在，使用现有买家", "buyer_id": buyer_id}
                            }
                        else:
                            return {
                                "success": False,
                                "error": f"买家已存在但获取失败: {existing_buyer.get('error', '未知错误')}"
                            }
                    except Exception as e:
                        return {
                            "success": False,
                            "error": f"买家已存在但获取失败: {str(e)}"
                        }
                else:
                    # 其他错误
                    return {
                        "success": False,
                        "error": buyer_data.get('message', '创建买家失败')
                    }
            
            return {
                "success": True,
                "buyer_id": buyer_data.get('id') or buyer_data.get('buyerId') or buyer_data.get('buyer_id'),
                "data": buyer_data
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 创建买家失败: {str(e)}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def create_checkout(self, buyer_id: str, amount: float, currency: str, **kwargs) -> Dict[str, Any]:
        """创建40Seas结账表单"""
        try:
            checkout_data = self.client.create_checkout(
                buyer_id=buyer_id,
                amount=amount,
                currency=currency,
                metadata=kwargs.get('metadata', {})
            )

            checkout_id = checkout_data.get('id') or checkout_data.get('checkoutId') or checkout_data.get('checkout_id')
            if not checkout_id:
                # 没有返回 checkout_id，视为失败，方便上层报错而不是继续用 None
                frappe.logger().error(f"[40Seas] 创建结账失败，未返回 checkout_id，响应: {checkout_data}")
                return {
                    "success": False,
                    "error": f"Invalid checkout response, no checkout_id: {checkout_data}",
                    "data": checkout_data,
                }
            
            return {
                "success": True,
                "checkout_id": checkout_id,
                "data": checkout_data
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 创建结账失败: {str(e)}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def create_payment_intent(self, checkout_id: str, **kwargs) -> Dict[str, Any]:
        """创建40Seas支付意图"""
        try:
            intent_data = self.client.create_payment_intent(checkout_id)
            
            frappe.logger().error(f"[40Seas] create_payment_intent 响应: {intent_data}")

            # 有 token/url 才认为成功，否则视为失败，方便上层捕获
            if intent_data.get('token') or intent_data.get('url'):
                return {
                    "success": True,
                    "payment_token": intent_data.get('token'),
                    "payment_url": intent_data.get('url'),
                    "data": intent_data
                }
            else:
                return {
                    "success": False,
                    "error": f"Invalid payment intent response: {intent_data}",
                    "data": intent_data,
                }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 创建支付意图失败: {str(e)}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def get_payment_status(self, checkout_id: str) -> Dict[str, Any]:
        """获取40Seas支付状态"""
        try:
            status_data = self.client.get_checkout_status(checkout_id)
            
            return {
                "success": True,
                "status": status_data.get('status'),
                "data": status_data
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 获取支付状态失败: {str(e)}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def handle_webhook(self, payload: Dict[str, Any]) -> Dict[str, Any]:
        """处理40Seas Webhook"""
        try:
            event_type = payload.get('type')
            checkout_id = payload.get('data', {}).get('id')
            
            frappe.logger().info(f"[40Seas Webhook] 收到事件: {event_type}, Checkout ID: {checkout_id}")
            
            # 根据事件类型处理
            if event_type in ['checkout.confirmed', 'checkout.marked_as_paid']:
                return self._handle_payment_success(checkout_id, payload)
            elif event_type == 'checkout.failed':
                return self._handle_payment_failed(checkout_id, payload)
            elif event_type == 'checkout.canceled':
                return self._handle_payment_canceled(checkout_id, payload)
            else:
                frappe.logger().info(f"[40Seas Webhook] 未处理的事件类型: {event_type}")
                return {"success": True, "message": "事件已接收但未处理"}
                
        except Exception as e:
            frappe.logger().error(f"[40Seas Webhook] 处理失败: {str(e)}")
            return {"success": False, "error": str(e)}
    
    def _handle_payment_success(self, checkout_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付成功"""
        try:
            # 1. 查找对应的支付记录
            payment_docs = frappe.db.sql("""
                SELECT name FROM `taboms_payment` 
                WHERE checkout_id = %s
            """, (checkout_id,), as_dict=True)
            
            if not payment_docs:
                frappe.logger().error(f"[40Seas] 未找到checkout_id为{checkout_id}的支付记录")
                return {"success": False, "error": "Payment record not found"}
            
            payment_doc = frappe.get_doc("oms_payment", payment_docs[0].name)
            
            # 2. 验证支付金额是否完整
            expected_amount = payment_doc.amount
            paid_amount = payload.get('amount', 0)
            
            if abs(paid_amount - expected_amount) > 0.01:  # 允许1分钱的误差
                frappe.logger().error(f"[40Seas] 支付金额不匹配: 期望{expected_amount}, 实际{paid_amount}")
                return {"success": False, "error": f"Payment amount mismatch, expected {expected_amount}, actual {paid_amount}"}
            
            # 3. 更新支付状态为已支付
            payment_doc.status = "confirmed"
            payment_doc.notification_status = "sent"
            
            # 4. 记录成功信息到payment_data字段
            if hasattr(payment_doc, 'payment_data') and payment_doc.payment_data:
                try:
                    payment_data = json.loads(payment_doc.payment_data) if isinstance(payment_doc.payment_data, str) else payment_doc.payment_data
                except:
                    payment_data = {}
            else:
                payment_data = {}
            
            # 添加成功信息到payment_data
            payment_data['success_time'] = datetime.datetime.utcnow().isoformat() + "Z"
            payment_data['success_payload'] = payload
            payment_data['paid_amount'] = paid_amount
            
            # 更新payment_data字段
            payment_doc.payment_data = json.dumps(payment_data)
            
            payment_doc.save(ignore_permissions=True)
            
            frappe.logger().info(f"[40Seas] 支付成功: {checkout_id}, 金额: {paid_amount}")
            
            # 4. 可以在这里添加其他业务逻辑
            # 例如：发送确认邮件、更新订单状态等
            
            return {
                "success": True, 
                "message": "Payment success processed",
                "payment_id": payment_doc.name,
                "amount": paid_amount
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 处理支付成功失败: {str(e)}")
            return {"success": False, "error": f"处理支付成功失败: {str(e)}"}
    
    def _handle_payment_failed(self, checkout_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付失败"""
        try:
            # 1. 查找对应的支付记录
            payment_docs = frappe.db.sql("""
                SELECT name FROM `taboms_payment` 
                WHERE checkout_id = %s
            """, (checkout_id,), as_dict=True)
            
            if not payment_docs:
                frappe.logger().error(f"[40Seas] 未找到checkout_id为{checkout_id}的支付记录")
                return {"success": False, "error": "Payment record not found"}
            
            payment_doc = frappe.get_doc("oms_payment", payment_docs[0].name)
            
            # 2. 更新支付状态为失败
            payment_doc.status = "failed"
            payment_doc.notification_status = "failed"
            
            # 3. 记录失败原因到payment_data字段
            failure_reason = payload.get('error_message') or payload.get('reason') or 'Payment failed'
            
            # 获取现有的payment_data或创建新的
            if hasattr(payment_doc, 'payment_data') and payment_doc.payment_data:
                try:
                    payment_data = json.loads(payment_doc.payment_data) if isinstance(payment_doc.payment_data, str) else payment_doc.payment_data
                except:
                    payment_data = {}
            else:
                payment_data = {}
            
            # 添加失败信息到payment_data
            payment_data['failure_reason'] = failure_reason
            payment_data['failure_time'] = datetime.datetime.utcnow().isoformat() + "Z"
            payment_data['failure_payload'] = payload
            
            # 更新payment_data字段
            payment_doc.payment_data = json.dumps(payment_data)
            
            payment_doc.save(ignore_permissions=True)
            
            frappe.logger().warning(f"[40Seas] 支付失败: {checkout_id}, 支付记录: {payment_doc.name}")
            
            return {
                "success": True, 
                "message": "Payment failure processed",
                "payment_id": payment_doc.name
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 处理支付失败异常: {str(e)}")
            return {"success": False, "error": f"处理支付失败异常: {str(e)}"}
    
    def _handle_payment_canceled(self, checkout_id: str, payload: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付取消 - 保持记录等待重新支付"""
        try:
            # 1. 查找对应的支付记录
            payment_docs = frappe.db.sql("""
                SELECT name FROM `taboms_payment` 
                WHERE checkout_id = %s
            """, (checkout_id,), as_dict=True)
            
            if not payment_docs:
                frappe.logger().error(f"[40Seas] 未找到checkout_id为{checkout_id}的支付记录")
                return {"success": False, "error": "Payment record not found"}
            
            payment_doc = frappe.get_doc("oms_payment", payment_docs[0].name)
            
            # 2. 对于强制全款支付，取消状态意味着客户还没有完成支付
            # 保持记录状态为pending，等待客户重新支付
            # 不更新任何状态，让记录保持原状
            
            frappe.logger().info(f"[40Seas] 支付取消 - 保持记录等待重新支付: {checkout_id}, 支付记录: {payment_doc.name}")
            
            return {
                "success": True, 
                "message": "Payment cancelled - record kept for retry",
                "payment_id": payment_doc.name,
                "status": "pending"  # 明确返回pending状态
            }
            
        except Exception as e:
            frappe.logger().error(f"[40Seas] 处理支付取消异常: {str(e)}")
            return {"success": False, "error": f"处理支付取消异常: {str(e)}"}


